/*****************************************************************************************************************
 * memory_bit_stream.cpp
 * 描述:参考多人网络游戏框架代码编写, 主要实现数据的序列化与反序列化.
 * 作者:xhome
 * 时间:2020/5/20
 ****************************************************************************************************************/

#ifndef MEMORYBITSTREAM_MEMORY_BIT_STREAM_H
#define MEMORYBITSTREAM_MEMORY_BIT_STREAM_H

#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>

//precision 精度
inline uint32_t convert_to_fixed(float in_number, float in_min, float in_precision)
{
    return static_cast<int>((in_number - in_min)/in_precision);
}

inline float convert_from_fixed(uint32_t in_number, float in_min, float in_precision)
{
    return static_cast<float>(in_number)*in_precision + in_min;
}

class OutputMemoryBitStream
{
public:
    OutputMemoryBitStream():
    bit_head_(0), buffer_(nullptr)
    {
        realloc_buffer(1500*8); //1500字节
    }

    ~OutputMemoryBitStream()
    {
        std::free(buffer_);
    }
    void write_bits(uint8_t in_data, uint32_t in_bit_count);
    void write_bits(const void * in_data, uint32_t in_bit_count);

    const char  * get_buffer()     const { return buffer_;}
    uint32_t      get_bit_length() const { return  bit_head_;}
    uint32_t      get_byte_length() const { return  (bit_head_ + 7) >> 3;}

    void write_bytes(const void * in_data, uint32_t in_byte_count)
    {
        write_bits(in_data, in_byte_count << 3);
    }

    //实现写模板方法, 按位进行写入.
    template <typename  T>
    void write(T in_data, uint32_t in_bit_count = sizeof(T)*8)
    {
        //判断类型是否合法.
        static_assert(std::is_arithmetic<T>::value || std::is_enum<T>::value, "Generic write only supports primitive data types");
        write_bits(&in_data, in_bit_count);
    }

    void write(bool in_data)
    {
        write_bits(&in_data, 1);
    }

    void write(const std::string & in_string)
    {
        uint32_t element_count = static_cast<uint32_t >(in_string.size());
        write(element_count);  //调用模板方法.
        for(const auto & element:in_string)
        {
            write(element);
        }
    }

private:
    void realloc_buffer(uint32_t in_new_bit_length);
    char *   buffer_;
    uint32_t bit_head_;
    uint32_t bit_capacity_;
};

class InputMemoryBitStream
{
public:
    InputMemoryBitStream(char * in_buffer, uint32_t in_bit_count):
    buffer_(in_buffer), bit_capacity_(in_bit_count), bit_head_(0),is_buffer_owner_(true)
    {

    }

    InputMemoryBitStream(const InputMemoryBitStream & in_other):
    bit_capacity_(in_other.bit_capacity_), bit_head_(in_other.bit_head_),is_buffer_owner_(in_other.is_buffer_owner_)
    {
        int byte_count = bit_capacity_ / 8;
        buffer_ = static_cast<char *>(malloc(byte_count));
        //拷贝
        memcpy(buffer_, in_other.buffer_, byte_count);
    }

    ~InputMemoryBitStream()
    {

        if(is_buffer_owner_){
         //   std::free(buffer_);
        }
    }

    const char * get_buffer() const
    {
        return buffer_;
    }

    uint32_t get_remaining_bit_count() const
    {
        return bit_capacity_ - bit_head_;
    }

    void read_bits(uint8_t & out_data, uint32_t in_bit_count);
    void read_bits(void * out_data, uint32_t in_bit_count);
    void read_bytes(void * out_data, uint32_t in_byte_count)
    {
        read_bits(out_data, in_byte_count << 3);
    }

    template <typename T>
    void read(T & in_data, uint32_t in_bit_count= sizeof(T)*8)
    {
        static_assert(std::is_arithmetic<T>::value || std::is_enum<T>::value, "Generic read only support primitive data types");
        read_bits(&in_data, in_bit_count);
    }

    void read(uint32_t & out_data, uint32_t in_bit_count=32){
        read_bits(&out_data, in_bit_count);
    }
    void read(int & out_data, uint32_t in_bit_count=32){
        read_bits(&out_data, in_bit_count);
    }

    void read(float & out_data){
        read_bits(&out_data, 32);
    }

    void read(uint16_t & out_data, uint32_t in_bit_count=16){
        read_bits(&out_data, in_bit_count);
    }
    void read(int16_t & out_data, uint32_t in_bit_count=16){
        read_bits(&out_data, in_bit_count);
    }

    void read(bool & out_data){
        read_bits(&out_data, 1);
    }

    void reset_to_capacity(uint32_t in_byte_capacity){
        bit_capacity_ = in_byte_capacity << 3;
        bit_head_ = 0;
    }

    void read(std::string & in_string){
        uint32_t element_count;
        read(element_count);
        in_string.resize(element_count);

        for(auto& element:in_string){
            read(element);
        }
    }


private:
    char *    buffer_;
    uint32_t  bit_head_;
    uint32_t  bit_capacity_;
    bool      is_buffer_owner_;
};




#endif //MEMORYBITSTREAM_MEMORY_BIT_STREAM_H
